/*************************************************************************
	> File Name: test10.cc
	> Author: H.M. Lau
	> Mail: hm.lau@outlook.com
	> Created Time: 2023/09/24 22:20
 ************************************************************************/

#include <iostream>
#include <string>
#include <unistd.h>
#include <pthread.h>

#define TNUM 4
typedef void (*func_t) (const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond);
volatile bool quit = false;

class ThreadData
{
public:
    ThreadData (const std::string &name, func_t func, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
    :_name(name), _func(func), _pmtx(pmtx), _pcond(pcond)
    {}
    std::string _name;
    func_t _func;
    pthread_mutex_t *_pmtx;
    pthread_cond_t *_pcond;
};

void func1(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit) {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << name << " running -- Open." << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func2(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit) {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << name << " running -- Download." << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func3(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit) {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << name << " running -- Reflash." << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void func4(const std::string &name, pthread_mutex_t *pmtx, pthread_cond_t *pcond)
{
    while (!quit) {
        pthread_mutex_lock(pmtx);
        pthread_cond_wait(pcond, pmtx);
        std::cout << name << " running -- Scan." << std::endl;
        pthread_mutex_unlock(pmtx);
    }
}

void *Entry(void *args)
{
    ThreadData *td = (ThreadData*)args;
    td->_func(td->_name, td->_pmtx, td->_pcond);
    delete td;
    return nullptr;
}

int main(int argc, char *argv[])
{
    pthread_mutex_t mtx;
    pthread_cond_t cond;
    pthread_mutex_init(&mtx, nullptr);
    pthread_cond_init(&cond, nullptr);
    pthread_t tids[TNUM];
    func_t funcs[TNUM] = {func1, func2, func3, func4};
    for (int i = 0; i < TNUM; ++i) {
        std::string name = "Thread";
        name += std::to_string(i + 1);
        ThreadData *td = new ThreadData(name, funcs[i], &mtx, &cond);
        pthread_create(tids + i, nullptr, Entry, (void*)td);
    }
    sleep(5);
    int cnt = 10;
    while (cnt) {
        std::cout << "Resume thread run code..." << cnt-- << std::endl;
        pthread_cond_broadcast(&cond);
        sleep(1);
    }
    std::cout << "ctrl done" << std::endl;
    quit = true;
    pthread_cond_broadcast(&cond);
    for (int i = 0; i < TNUM; ++i) {
        pthread_join(tids[i], nullptr);
        std::cout << "Thread:" << tids[i] << " quit." << std::endl;
    }
    pthread_mutex_destroy(&mtx);
    pthread_cond_destroy(&cond);
    return 0;
}
